#include "PointCloud.h"
#include "../View/View.h"

#include <fstream>
#include <sstream>

using namespace std;
using namespace CICore;

/// <summary>
/// Constructor
/// </summary>
/// <param name="n"> The point cloud name </param>
CIGeom::PointCloud::PointCloud (const char* n) : Geometry (n) {}

/// <summary>
/// Constructor
/// </summary>
/// <param name="n"> The point cloud name </param>
CIGeom::PointCloud::PointCloud (const string& n) : Geometry (n) {}

/// <summary>
/// Destructor
/// </summary>
CIGeom::PointCloud::~PointCloud() {
}








///<************************************************************************************************************>
///<**************************************** region Utility Methods ********************************************>
///<************************************************************************************************************>

/// <summary>
/// Method called to render the point cloud
/// </summary>
/// <param name="selectionMode"> The selection mode active in the scene </param>
void CIGeom::PointCloud::Render (unsigned int selectionMode) {
    VertexIter vertexIt = vertices.begin();
    Vertex* v = 0;

    bool lightingEnabled = glIsEnabled (GL_LIGHTING);
    if (lightingEnabled)
        glDisable (GL_LIGHTING);

    glPointSize (POINT_SIZE);                             //Sets the point size

    //Drawing the selected vertices
    glBegin (GL_POINTS);
        while (vertexIt != vertices.end()) {        //For each vertex
            v = *vertexIt;

            if (v->visible) {
                //Chosing the vertex color depending on whether the vertex is selected or not
                if (v->selected)
                     glColor3f (VERTEX_SELECTED_COLOR.r, VERTEX_SELECTED_COLOR.g, VERTEX_SELECTED_COLOR.b);  
                else
                     glColor3f (0.8f, 0.8f, 0.8f);  

                glNormal3f (v->normal.x, v->normal.y, v->normal.z);          //Sets the vertex normal
                                        
                glVertex3f( v->x, v->y, v->z );     //draws the vertex
            }

            vertexIt++;
        }
    glEnd();
    
    //TODO -> bounding box must be renderizable
    //boundingBox.Render();
   
    if (lightingEnabled)
        glEnable (GL_LIGHTING);
}

/// <summary>
/// Method called to load the names that identify this geometry in the OpenGL names stack
/// </summary>
void CIGeom::PointCloud::LoadNames() {
    LoadVerticesNames();
}

/// <summary>
/// Method called to get the number of names that identify this geometry 
/// </summary>
int CIGeom::PointCloud::GetNumberOfNames() {
    return vertices.size();
}

/// <summary>
/// Method called to load the faces names in the OpenGL names stack
/// </summary>
void CIGeom::PointCloud::LoadFacesNames() {}

/// <summary>
/// Method called to load the vertices names in the OpenGL names stack
/// </summary>
void CIGeom::PointCloud::LoadVerticesNames() {
    VertexIter it = vertices.begin();
    Vertex* v = 0;
    unsigned int vertexIndex = 0;

    //Drawing the selected vertices
    while (it != vertices.end()) {              //For each vertex
        v = *it;

        if (v->visible) {
            glLoadName (vertexIndex);               //Load a name in the OpenGL names stack for the current vertex 
            
            glNormal3f (v->normal.x, v->normal.y, v->normal.z);          //Sets the vertex normal

            glBegin (GL_POINTS);
                glVertex3f( v->x, v->y, v->z );     //Draws the vertex
            glEnd();
        }

        vertexIndex++;
        it++;
    }
}

/// <summary>
/// Method called to save a description of this geometry within an output stream
/// </summary>
/// <param name="device"> The file to save the geometry description </param>
void CIGeom::PointCloud::SaveAsCI3D (std::ofstream& out) {
    const char* tab = "    ";

    stringstream stream;

    stream << tab << tab << tab << "<geometry name=\"" << name.c_str() << "\">\n";

    stream << tab << tab << tab << tab << "<point_cloud>\n";

    stream << tab << tab << tab << tab << tab << "<vertices size=\"" << vertices.size() << "\">\n";

    Vertex* v;

    for (int i=0; i<vertices.size(); i++) {         //For each vertex
        v = vertices[i];

        stream << tab << tab << tab << tab << tab << tab << "<v x=\"" << v->x 
                                                         << "\" y=\"" << v->y 
                                                         << "\" z=\"" << v->z  
                                                         << "\"/>\n";
    }

    stream << tab << tab << tab << tab << tab << "</vertices>\n";

    stream << tab << tab << tab << tab << "</point_cloud>\n";

    stream << tab << tab << tab << "</geometry>\n";
    
    out << stream.rdbuf();
}
/***************************************************************************************************************
******************************************* endregion Utility Methods ******************************************
****************************************************************************************************************/
